﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YouVisio.Silverlight.TextDiff;
using YouVisio.Silverlight.TextDiffTests.Utils;

namespace YouVisio.Silverlight.TextDiffTests
{
    [TestClass]
    public class DiffAnalyser_Tests : BaseTestClass
    {
        #region Analyse Tests with LettersRetriever
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Square_Case()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "adef12g");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Equal=1; Delete=2; Equal=3; Insert=2; Equal=1", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_1()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "12a3");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Insert=2; Equal=1; Change=1; Delete=5", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_2()
        {
            var state = GetLetterPartsAggregationState("1ab3", "abcdefg");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Delete=1; Equal=2; Change=1; Insert=4", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_3()
        {
            var state = GetLetterPartsAggregationState("1234", "abcdefg");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Change=4; Insert=3", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_4()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "1234");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Change=4; Delete=3", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_5()
        {
            var state = GetLetterPartsAggregationState("abcd", "abc");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Equal=3; Delete=1", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_As_Expected_In_Rectangular_Case_6()
        {
            var state = GetLetterPartsAggregationState("abc", "abcd");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Equal=3; Insert=1", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_If_Missing_Left_Part()
        {
            var state = GetLetterPartsAggregationState("", "12345");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Insert=5", list.ToDescriptiveString());
        }
        [TestMethod]//[Ignore]
        public void Can_Analyse_Char_Parts_If_Missing_Right_Part()
        {
            var state = GetLetterPartsAggregationState("12345", "");

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Delete=5", list.ToDescriptiveString());
        }
        #endregion
        #region Analyse Tests with Int32Retriever
        [TestMethod]//[Ignore]
        public void Can_Analyse_Int32_Parts_As_Expected_In_Rectangular_Case_1()
        {
            var state = GetInt32PartsAggregationState(new[] { 0, 1, 2 }, new[] { 0, 1, 2, 3 });

            var list = new DiffAnalyser().Analyse(state.Comparer, state.Before, state.After, state.InitialBeforeIndex, state.InitialAfterIndex, state.Length);

            Assert.AreEqual("Equal=3; Insert=1", list.ToDescriptiveString());
        }
        #endregion

        #region AggregateParts Tests

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Square_Case()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "adef12g");

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:0,0(-1,-1)|2:1,1(0,0)|3:2,2(0,0)|4:1,2(0,0)|5:2,1(0,0)|6:3,3(0,0)|7:2,3(0,0)|8:1,3(0,0)|9:3,2(0,0)|10:3,1(0,0)|11:4,2(3,1)|12:5,3(4,2)|13:6,4(5,3)|14:6,5(5,3)|15:6,6(5,3)|";

            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(15, state.Accumulator.State);
        }

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Rectangular_Case_1()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "12a3");

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:0,0(-1,-1)|2:1,1(-1,-1)|3:0,1(-1,-1)|4:1,0(-1,-1)|5:2,2(-1,-1)|6:1,2(-1,-1)|7:0,2(-1,-1)|8:1,3(0,2)|9:2,3(0,2)|10:3,3(0,2)|11:4,3(0,2)|12:5,3(0,2)|13:6,3(0,2)|";

            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(13, state.Accumulator.State);
        }

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Rectangular_Case_2()
        {
            var state = GetLetterPartsAggregationState("1ab3", "abcdefg");

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:0,0(-1,-1)|2:1,1(-1,-1)|3:0,1(-1,-1)|4:1,0(-1,-1)|5:2,1(1,0)|6:3,2(2,1)|7:3,3(2,1)|8:3,4(2,1)|9:3,5(2,1)|10:3,6(2,1)|";

            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(10, state.Accumulator.State);
        }

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Square_Case_With_Part_Existance_Lookup()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "adef12g");
            state.SkipToCheckIfPartExists = false;

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:0,0(-1,-1)|2:1,1(0,0)|3:2,2(0,0)|4:1,2(0,0)|5:3,3(0,0)|6:2,3(0,0)|7:1,3(0,0)|8:3,2(0,0)|9:3,1(0,0)|10:4,2(3,1)|11:5,3(4,2)|12:6,6(5,3)|";

            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(12, state.Accumulator.State);
        }

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Rectangular_Case_1_With_Part_Existance_Lookup()
        {
            var state = GetLetterPartsAggregationState("abcdefg", "12a3");
            state.SkipToCheckIfPartExists = false;

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:2,2(-1,-1)|2:1,2(-1,-1)|3:0,2(-1,-1)|";

            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(3, state.Accumulator.State);
        }

        [TestMethod]//[Ignore]
        public void Can_Aggregate_Parts_As_Expected_In_Rectangular_Case_2_With_Part_Existance_Lookup()
        {
            var state = GetLetterPartsAggregationState("1ab3", "abcdefg");
            state.SkipToCheckIfPartExists = false;

            state = new DiffAnalyser().AggregateParts(state);

            const string EXPECTED = "1:0,0(-1,-1)|2:1,1(-1,-1)|3:0,1(-1,-1)|4:1,0(-1,-1)|5:2,1(1,0)|";
            //Console.WriteLine(state.Accumulator);
            Assert.AreEqual(EXPECTED, state.Accumulator.ToString());
            Assert.AreEqual(5, state.Accumulator.State);
        }
        #endregion

        #region Private Methods
        private static PartsAggregationState<StringBuilderWithState<int>, int[], int> GetInt32PartsAggregationState(int[] one, int[] two)
        {
            return new PartsAggregationState<StringBuilderWithState<int>, int[], int>
            {
                Accumulator = new StringBuilderWithState<int>(0),
                Before = new Int32Retriever() { Source = one },
                After = new Int32Retriever { Source = two },
                Comparer = EqualityComparer<int>.Default,
                InitialBeforeIndex = -1,
                InitialAfterIndex = -1,
                Length = Int32.MaxValue,
                Function = s => s,
                Log = s => s.Accumulator.AppendFormat("{0}:{1},{2}({3},{4})|", ++s.Accumulator.State, s.CurrentBeforeIndex, s.CurrentAfterIndex, s.LastMatchBeforeIndex, s.LastMatchAfterIndex),
                SkipToCheckIfPartExists = true
            };
        }
        private static PartsAggregationState<StringBuilderWithState<int>, string, char> GetLetterPartsAggregationState(string one, string two)
        {
            return new PartsAggregationState<StringBuilderWithState<int>, string, char>
            {
                Accumulator = new StringBuilderWithState<int>(0),
                Before = new LettersRetriever { Source = one },
                After = new LettersRetriever { Source = two },
                Comparer = EqualityComparer<char>.Default,
                InitialBeforeIndex = -1,
                InitialAfterIndex = -1,
                Length = Int32.MaxValue,
                Function = s => s,
                Log = s => s.Accumulator.AppendFormat("{0}:{1},{2}({3},{4})|", ++s.Accumulator.State, s.CurrentBeforeIndex, s.CurrentAfterIndex, s.LastMatchBeforeIndex, s.LastMatchAfterIndex),
                SkipToCheckIfPartExists = true
            };
        }
        #endregion
    }
}